/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include "hmi_pg_def.h"
#include "hmi_theme.h"
#include "hmi_pg_wrap.h"
#include "hmi_asset.h"
#include "hmi_subject.h"
#include "hmi_pg_navigation.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/
typedef struct
{
    char *icon;
    char *title;
    hmi_pg_t *pg;
} function_t;

typedef enum
{
    FUNCTION_LED_STRIP,
    FUNCTION_NUM,
} function_enum_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void create();
static void del();
static void open();
static void close();

static void clock_update_cb(lv_observer_t *observer, lv_subject_t *subject);
static void date_update_cb(lv_observer_t *observer, lv_subject_t *subject);
static void weather_update_cb(lv_observer_t *observer, lv_subject_t *subject);
static void weather_icon_update_cb(lv_observer_t *observer, lv_subject_t *subject);
static void anim_exec_xcb(void *obj, int32_t val);
static void del_ev_cb(lv_event_t *e);
static void function_clicked_cb(lv_event_t *e);

/**********************
 *  STATIC VARIABLES
 **********************/
static hmi_pg_t home = {
    .name = "主页",
    .create = create,
    .del = del,
    .open = open,
    .close = close};

static lv_font_t *clock_font;
static lv_font_t *date_font;
static lv_font_t *weather_font;
static lv_font_t *function_font;

static lv_obj_t *weather_wrap;
static lv_obj_t *function_wrap;

static function_t functions[FUNCTION_NUM] = {
    {.icon = "lightbulb", .title = "灯带"},
};
/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
hmi_pg_t *hmi_pg_home()
{
    return &home;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void create()
{
    if (home.root)
        lv_obj_del(home.root);

    home.root = lv_obj_create(NULL);
    lv_obj_add_style(home.root, &hmi_g_wrap_style, 0);

    lv_obj_t *wrap = hmi_pg_wrap_create(home.root);
    lv_obj_add_style(wrap, &hmi_g_wrap_style, 0);
    lv_obj_set_flex_flow(wrap, LV_FLEX_FLOW_COLUMN);

    weather_wrap = lv_obj_create(wrap);
    lv_obj_remove_style_all(weather_wrap);
    lv_obj_add_style(weather_wrap, &hmi_g_wrap_style, 0);
    lv_obj_set_flex_grow(weather_wrap, 1);
    lv_obj_set_width(weather_wrap, lv_pct(100));
    lv_obj_add_event_cb(weather_wrap, del_ev_cb, LV_EVENT_DELETE, NULL);

    lv_obj_update_layout(weather_wrap);
    int32_t h = lv_obj_get_height(weather_wrap);

    int32_t font_height = h * 0.28;
    clock_font = hmi_ttf_create_static("clock_font", font_height, 0);
    lv_obj_t *clock = lv_label_create(weather_wrap);
    lv_obj_set_style_text_font(clock, clock_font, 0);
    lv_obj_align(clock, LV_ALIGN_TOP_LEFT, 0, -10);
    lv_label_set_recolor(clock, true);

    font_height = h * 0.08;
    date_font = hmi_ttf_create_static("def_font", font_height, 0);
    lv_obj_t *date = lv_label_create(weather_wrap);
    lv_obj_set_style_text_font(date, date_font, 0);
    lv_obj_align(date, LV_ALIGN_BOTTOM_LEFT, 10, 0);
    lv_label_set_recolor(date, true);

    weather_font = hmi_ttf_create_static("def_font", font_height, 0);
    lv_obj_t *weather = lv_label_create(weather_wrap);
    lv_obj_set_style_text_font(weather, weather_font, 0);
    lv_obj_align(weather, LV_ALIGN_BOTTOM_RIGHT, -10, 0);
    lv_obj_set_style_text_align(weather, LV_TEXT_ALIGN_RIGHT, 0);
    lv_label_set_recolor(weather, true);

    lv_area_t c;
    lv_obj_get_coords(weather_wrap, &c);

    lv_obj_t *weather_icon = lv_image_create(weather_wrap);
    lv_obj_align(weather_icon, LV_ALIGN_TOP_RIGHT, -10, 0);
    lv_image_set_pivot(weather_icon, c.x2, c.y1);

    function_wrap = lv_obj_create(wrap);
    lv_obj_remove_style_all(function_wrap);
    lv_obj_add_style(function_wrap, &hmi_g_wrap_style, 0);
    lv_obj_set_flex_grow(function_wrap, 1);
    lv_obj_set_width(function_wrap, lv_pct(100));
    lv_obj_add_event_cb(function_wrap, del_ev_cb, LV_EVENT_DELETE, NULL);
    lv_obj_set_flex_flow(function_wrap, LV_FLEX_FLOW_ROW);
    lv_obj_set_style_pad_all(function_wrap, 10, 0);

    lv_obj_update_layout(function_wrap);
    font_height = lv_obj_get_height(function_wrap) * 0.16;
    function_font = hmi_ttf_create_static("def_font", font_height, true);

    for (size_t i = 0; i < FUNCTION_NUM; i++)
    {
        lv_obj_t *btn = lv_btn_create(function_wrap);
        lv_obj_add_style(btn, &hmi_g_wrap_style, 0);
        lv_obj_set_height(btn, lv_pct(100));
        lv_obj_set_style_pad_all(btn, 10, 0);
        lv_obj_set_style_shadow_width(btn, 0, 0);
        lv_obj_add_event_cb(btn, function_clicked_cb, LV_EVENT_CLICKED, functions[i].pg);

        lv_obj_update_layout(btn);
        int32_t w = lv_obj_get_height(btn) * 1.5;
        lv_obj_set_width(btn, w);

        lv_obj_set_style_bg_color(btn, lv_palette_main(LV_PALETTE_GREY), 0);
        lv_obj_set_style_bg_opa(btn, LV_OPA_20, 0);

        lv_obj_t *icon_wrap = lv_obj_create(btn);
        lv_obj_remove_style_all(icon_wrap);
        lv_obj_set_size(icon_wrap, w * 0.3, w * 0.3);
        lv_obj_set_style_radius(icon_wrap, LV_RADIUS_CIRCLE, 0);
        lv_obj_set_style_bg_opa(icon_wrap, LV_OPA_COVER, 0);
        lv_obj_align(icon_wrap, LV_ALIGN_TOP_LEFT, 0, 0);

        lv_obj_t *icon = lv_img_create(icon_wrap);
        lv_image_set_src(icon, hmi_png(functions[i].icon));
        lv_obj_set_style_img_recolor_opa(icon, LV_OPA_COVER, 0);
        lv_obj_set_style_img_recolor(icon, lv_color_hex(0xff5722), 0);
        lv_obj_center(icon);

        lv_obj_t *title = lv_label_create(btn);
        lv_obj_set_style_text_font(title, function_font, 0);
        lv_label_set_text(title, lv_tr(functions[i].title));
        lv_obj_align(title, LV_ALIGN_BOTTOM_LEFT, 0, 0);
    }

    lv_subject_add_observer_obj(&hmi_time_subj, clock_update_cb, clock, NULL);
    lv_subject_add_observer_obj(&hmi_time_subj, date_update_cb, date, NULL);
    lv_subject_add_observer_obj(&hmi_weather_subj, weather_update_cb, weather, NULL);
    lv_subject_add_observer_obj(&hmi_weather_subj, weather_icon_update_cb, weather_icon, NULL);
}

static void del()
{
    hmi_ttf_del(clock_font);
    hmi_ttf_del(date_font);
    hmi_ttf_del(weather_font);
    hmi_ttf_del(function_font);
    clock_font = NULL;
    date_font = NULL;
    weather_font = NULL;
    function_font = NULL;

    lv_obj_clean(home.root);
}

static void open()
{
    lv_screen_load(home.root);

    static int32_t y;
    static bool flag = 1;
    if (flag)
    {
        lv_obj_update_layout(weather_wrap);
        y = lv_obj_get_y(weather_wrap);
        flag = 0;
    }

    lv_obj_fade_in(weather_wrap, 500 * hmi_g_anim_rate, 0);
    lv_obj_fade_in(function_wrap, 500 * hmi_g_anim_rate, 250);

    lv_anim_t a1;
    lv_anim_init(&a1);
    lv_anim_set_var(&a1, weather_wrap);
    lv_anim_set_exec_cb(&a1, anim_exec_xcb);
    lv_anim_set_values(&a1, y - 40, y);
    lv_anim_set_path_cb(&a1, lv_anim_path_ease_out);
    lv_anim_set_time(&a1, 500 * hmi_g_anim_rate);
    lv_anim_start(&a1);
}

static void close()
{
}

static void clock_update_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target_obj(observer);

    lv_subject_t *hour_subj = lv_subject_get_group_element(subject, 4);
    lv_subject_t *minute_subj = lv_subject_get_group_element(subject, 5);

    int32_t hour = lv_subject_get_int(hour_subj);
    int32_t minute = lv_subject_get_int(minute_subj);

    lv_label_set_text_fmt(obj, "#ff5722 %02d#:%02d", hour, minute);
}

static void date_update_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target_obj(observer);

    lv_subject_t *year_subj = lv_subject_get_group_element(subject, 0);
    lv_subject_t *month_subj = lv_subject_get_group_element(subject, 1);
    lv_subject_t *day_subj = lv_subject_get_group_element(subject, 2);
    lv_subject_t *weekday_subj = lv_subject_get_group_element(subject, 3);

    int32_t year = lv_subject_get_int(year_subj);
    int32_t month = lv_subject_get_int(month_subj);
    int32_t day = lv_subject_get_int(day_subj);
    int32_t weekday = lv_subject_get_int(weekday_subj);

    const char *weekday_str[] = {lv_tr("星期一"), lv_tr("星期二"), lv_tr("星期三"), lv_tr("星期四"), lv_tr("星期五"), lv_tr("星期六"), lv_tr("星期日")};

    lv_label_set_text_fmt(obj, "%d-%d-%d #ff5722 %s#", year, month, day, weekday_str[weekday]);
}

static void weather_update_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target_obj(observer);

    lv_subject_t *city_subj = lv_subject_get_group_element(subject, 0);
    lv_subject_t *text_day_subj = lv_subject_get_group_element(subject, 1);
    lv_subject_t *text_night_subj = lv_subject_get_group_element(subject, 3);
    lv_subject_t *high_subj = lv_subject_get_group_element(subject, 5);
    lv_subject_t *low_subj = lv_subject_get_group_element(subject, 6);

    int32_t high = lv_subject_get_int(high_subj);
    int32_t low = lv_subject_get_int(low_subj);

    lv_subject_t *hour_subj = lv_subject_get_group_element(&hmi_time_subj, 4);
    int32_t hour = lv_subject_get_int(hour_subj);

    if (hour >= 18 || hour < 6)
        lv_label_set_text_fmt(obj, "%d / %d\n%s· #ff5722 %s#", high, low, lv_tr(lv_subject_get_string(city_subj)), lv_tr(lv_subject_get_string(text_night_subj)));
    else if (hour >= 6 && hour < 18)
        lv_label_set_text_fmt(obj, "%d / %d\n%s· #ff5722 %s#", high, low, lv_tr(lv_subject_get_string(city_subj)), lv_tr(lv_subject_get_string(text_day_subj)));
}

static void weather_icon_update_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target_obj(observer);

    lv_subject_t *code_day_subj = lv_subject_get_group_element(subject, 2);
    lv_subject_t *code_night_subj = lv_subject_get_group_element(subject, 4);

    int32_t code_day = lv_subject_get_int(code_day_subj);
    int32_t code_night = lv_subject_get_int(code_night_subj);

    lv_subject_t *hour_subj = lv_subject_get_group_element(&hmi_time_subj, 4);
    int32_t hour = lv_subject_get_int(hour_subj);

    char icon[32];

    if (hour >= 18 || hour < 6)
        lv_snprintf(icon, 32, "%d@1x", code_night);
    else if (hour >= 6 && hour < 18)
        lv_snprintf(icon, 32, "%d@1x", code_day);
    else
        lv_snprintf(icon, 32, "99@1x");

    lv_image_set_src(obj, hmi_png(icon));
}

static void anim_exec_xcb(void *obj, int32_t val)
{
    lv_obj_set_style_translate_y(obj, val, 0);
}

static void del_ev_cb(lv_event_t *e)
{
    lv_obj_t *obj = lv_event_get_current_target(e);
    lv_anim_del(obj, NULL);
}

static void function_clicked_cb(lv_event_t *e)
{
    hmi_pg_t *pg = lv_event_get_user_data(e);

    if (pg)
        hmi_pg_push(pg);
}
